home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2007 January, February, March & April
/
Chip-Cover-CD-2007-02.iso
/
Pakiet multimedia
/
Muzyka
/
Edytory sampli (probek dzwieku)
/
ZynAddSubFX_2.2.0
/
Setup_ZynAddSubFX-2.2.0.exe
/
source code
/
Synth
/
ADnote.C
next >
Wrap
C/C++ Source or Header
|
2005-03-14
|
36KB
|
985 lines
/*
ZynAddSubFX - a software synthesizer
ADnote.C - The "additive" synthesizer
Copyright (C) 2002-2005 Nasca Octavian Paul
Author: Nasca Octavian Paul
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License (version 2) for more details.
You should have received a copy of the GNU General Public License (version 2)
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include "../globals.h"
#include "../Misc/Util.h"
#include "ADnote.h"
ADnote::ADnote(ADnoteParameters *pars,Controller *ctl_,REALTYPE freq,REALTYPE velocity,int portamento_,int midinote_){
ready=0;
tmpwave=new REALTYPE [SOUND_BUFFER_SIZE];
bypassl=new REALTYPE [SOUND_BUFFER_SIZE];
bypassr=new REALTYPE [SOUND_BUFFER_SIZE];
partparams=pars;
ctl=ctl_;
portamento=portamento_;
midinote=midinote_;
NoteEnabled=ON;
basefreq=freq;
if (velocity>1.0) velocity=1.0;
this->velocity=velocity;
time=0.0;
stereo=pars->GlobalPar.PStereo;
NoteGlobalPar.Detune=getdetune(pars->GlobalPar.PDetuneType
,pars->GlobalPar.PCoarseDetune,pars->GlobalPar.PDetune);
bandwidthDetuneMultiplier=pars->getBandwidthDetuneMultiplier();
if (pars->GlobalPar.PPanning==0) NoteGlobalPar.Panning=RND;
else NoteGlobalPar.Panning=pars->GlobalPar.PPanning/128.0;
NoteGlobalPar.FilterCenterPitch=pars->GlobalPar.GlobalFilter->getfreq()+//center freq
pars->GlobalPar.PFilterVelocityScale/127.0*6.0* //velocity sensing
(VelF(velocity,pars->GlobalPar.PFilterVelocityScaleFunction)-1);
if (pars->GlobalPar.PPunchStrength!=0) {
NoteGlobalPar.Punch.Enabled=1;
NoteGlobalPar.Punch.t=1.0;//start from 1.0 and to 0.0
NoteGlobalPar.Punch.initialvalue=( (pow(10,1.5*pars->GlobalPar.PPunchStrength/127.0)-1.0)
*VelF(velocity,pars->GlobalPar.PPunchVelocitySensing) );
REALTYPE time=pow(10,3.0*pars->GlobalPar.PPunchTime/127.0)/10000.0;//0.1 .. 100 ms
REALTYPE stretch=pow(440.0/freq,pars->GlobalPar.PPunchStretch/64.0);
NoteGlobalPar.Punch.dt=1.0/(time*SAMPLE_RATE*stretch);
} else NoteGlobalPar.Punch.Enabled=0;
for (int nvoice=0;nvoice<NUM_VOICES;nvoice++){
pars->VoicePar[nvoice].OscilSmp->newrandseed(rand());
NoteVoicePar[nvoice].OscilSmp=NULL;
NoteVoicePar[nvoice].FMSmp=NULL;
NoteVoicePar[nvoice].VoiceOut=NULL;
NoteVoicePar[nvoice].FMVoice=-1;
if (pars->VoicePar[nvoice].Enabled==0) {
NoteVoicePar[nvoice].Enabled=OFF;
continue; //the voice is disabled
};
NoteVoicePar[nvoice].Enabled=ON;
NoteVoicePar[nvoice].fixedfreq=pars->VoicePar[nvoice].Pfixedfreq;
NoteVoicePar[nvoice].fixedfreqET=pars->VoicePar[nvoice].PfixedfreqET;
//use the Globalpars.detunetype if the detunetype is 0
if (pars->VoicePar[nvoice].PDetuneType!=0){
NoteVoicePar[nvoice].Detune=getdetune(pars->VoicePar[nvoice].PDetuneType
,pars->VoicePar[nvoice].PCoarseDetune,8192);//coarse detune
NoteVoicePar[nvoice].FineDetune=getdetune(pars->VoicePar[nvoice].PDetuneType
,0,pars->VoicePar[nvoice].PDetune);//fine detune
} else {
NoteVoicePar[nvoice].Detune=getdetune(pars->GlobalPar.PDetuneType
,pars->VoicePar[nvoice].PCoarseDetune,8192);//coarse detune
NoteVoicePar[nvoice].FineDetune=getdetune(pars->GlobalPar.PDetuneType
,0,pars->VoicePar[nvoice].PDetune);//fine detune
};
if (pars->VoicePar[nvoice].PFMDetuneType!=0){
NoteVoicePar[nvoice].FMDetune=getdetune(pars->VoicePar[nvoice].PFMDetuneType
,pars->VoicePar[nvoice].PFMCoarseDetune,pars->VoicePar[nvoice].PFMDetune);
} else {
NoteVoicePar[nvoice].FMDetune=getdetune(pars->GlobalPar.PDetuneType
,pars->VoicePar[nvoice].PFMCoarseDetune,pars->VoicePar[nvoice].PFMDetune);
};
oscposhi[nvoice]=0;oscposlo[nvoice]=0.0;
oscposhiFM[nvoice]=0;oscposloFM[nvoice]=0.0;
NoteVoicePar[nvoice].OscilSmp=new REALTYPE[OSCIL_SIZE+OSCIL_SMP_EXTRA_SAMPLES];//the extra points contains the first point
//Get the voice's oscil or external's voice oscil
int vc=nvoice;
if (pars->VoicePar[nvoice].Pextoscil!=-1) vc=pars->VoicePar[nvoice].Pextoscil;
if (!pars->GlobalPar.Hrandgrouping) pars->VoicePar[vc].OscilSmp->newrandseed(rand());
oscposhi[nvoice]=pars->VoicePar[vc].OscilSmp->get(NoteVoicePar[nvoice].OscilSmp,getvoicebasefreq(nvoice),
pars->VoicePar[nvoice].Presonance);
//I store the first elments to the last position for speedups
for (int i=0;i<OSCIL_SMP_EXTRA_SAMPLES;i++) NoteVoicePar[nvoice].OscilSmp[OSCIL_SIZE+i]=NoteVoicePar[nvoice].OscilSmp[i];
oscposhi[nvoice]+=(int)((pars->VoicePar[nvoice].Poscilphase-64.0)/128.0*OSCIL_SIZE+OSCIL_SIZE*4);
oscposhi[nvoice]%=OSCIL_SIZE;
NoteVoicePar[nvoice].FreqLfo=NULL;
NoteVoicePar[nvoice].FreqEnvelope=NULL;
NoteVoicePar[nvoice].AmpLfo=NULL;
NoteVoicePar[nvoice].AmpEnvelope=NULL;
NoteVoicePar[nvoice].VoiceFilter=NULL;
NoteVoicePar[nvoice].FilterEnvelope=NULL;
NoteVoicePar[nvoice].FilterLfo=NULL;
NoteVoicePar[nvoice].FilterCenterPitch=pars->VoicePar[nvoice].VoiceFilter->getfreq();
NoteVoicePar[nvoice].filterbypass=pars->VoicePar[nvoice].Pfilterbypass;
switch(pars->VoicePar[nvoice].PFMEnabled){
case 1:NoteVoicePar[nvoice].FMEnabled=MORPH;break;
case 2:NoteVoicePar[nvoice].FMEnabled=RING_MOD;break;
case 3:NoteVoicePar[nvoice].FMEnabled=PHASE_MOD;break;
case 4:NoteVoicePar[nvoice].FMEnabled=FREQ_MOD;break;
case 5:NoteVoicePar[nvoice].FMEnabled=PITCH_MOD;break;
default:NoteVoicePar[nvoice].FMEnabled=NONE;
};
NoteVoicePar[nvoice].FMVoice=pars->VoicePar[nvoice].PFMVoice;
NoteVoicePar[nvoice].FMFreqEnvelope=NULL;
NoteVoicePar[nvoice].FMAmpEnvelope=NULL;
//Compute the Voice's modulator volume (incl. damping)
REALTYPE fmvoldamp=pow(440.0/getvoicebasefreq(nvoice),pars->VoicePar[nvoice].PFMVolumeDamp/64.0-1.0);
switch (NoteVoicePar[nvoice].FMEnabled){
case PHASE_MOD:fmvoldamp=pow(440.0/getvoicebasefreq(nvoice),pars->VoicePar[nvoice].PFMVolumeDamp/64.0);
NoteVoicePar[nvoice].FMVolume=(exp(pars->VoicePar[nvoice].PFMVolume/127.0*FM_AMP_MULTIPLIER)-1.0)*fmvoldamp*4.0;
break;
case FREQ_MOD:NoteVoicePar[nvoice].FMVolume=(exp(pars->VoicePar[nvoice].PFMVolume/127.0*FM_AMP_MULTIPLIER)-1.0)*fmvoldamp*4.0;
break;
// case PITCH_MOD:NoteVoicePar[nvoice].FMVolume=(pars->VoicePar[nvoice].PFMVolume/127.0*8.0)*fmvoldamp;//???????????
// break;
default:if (fmvoldamp>1.0) fmvoldamp=1.0;
NoteVoicePar[nvoice].FMVolume=pars->VoicePar[nvoice].PFMVolume/127.0*fmvoldamp;
};
//Voice's modulator velocity sensing
NoteVoicePar[nvoice].FMVolume*=VelF(velocity,partparams->VoicePar[nvoice].PFMVelocityScaleFunction);
FMoldsmp[nvoice]=0.0;//this is for FM (integration)
firsttick[nvoice]=1;
NoteVoicePar[nvoice].DelayTicks=(int)((exp(pars->VoicePar[nvoice].PDelay/127.0*log(50.0))-1.0)/SOUND_BUFFER_SIZE/10.0*SAMPLE_RATE);
};
initparameters();
ready=1;
};
/*
* Kill a voice of ADnote
*/
void ADnote::KillVoice(int nvoice){
delete (NoteVoicePar[nvoice].OscilSmp);
if (NoteVoicePar[nvoice].FreqEnvelope!=NULL) delete(NoteVoicePar[nvoice].FreqEnvelope);
NoteVoicePar[nvoice].FreqEnvelope=NULL;
if (NoteVoicePar[nvoice].FreqLfo!=NULL) delete(NoteVoicePar[nvoice].FreqLfo);
NoteVoicePar[nvoice].FreqLfo=NULL;
if (NoteVoicePar[nvoice].AmpEnvelope!=NULL) delete (NoteVoicePar[nvoice].AmpEnvelope);
NoteVoicePar[nvoice].AmpEnvelope=NULL;
if (NoteVoicePar[nvoice].AmpLfo!=NULL) delete (NoteVoicePar[nvoice].AmpLfo);
NoteVoicePar[nvoice].AmpLfo=NULL;
if (NoteVoicePar[nvoice].VoiceFilter!=NULL) delete (NoteVoicePar[nvoice].VoiceFilter);
NoteVoicePar[nvoice].VoiceFilter=NULL;
if (NoteVoicePar[nvoice].FilterEnvelope!=NULL) delete (NoteVoicePar[nvoice].FilterEnvelope);
NoteVoicePar[nvoice].FilterEnvelope=NULL;
if (NoteVoicePar[nvoice].FilterLfo!=NULL) delete (NoteVoicePar[nvoice].FilterLfo);
NoteVoicePar[nvoice].FilterLfo=NULL;
if (NoteVoicePar[nvoice].FMFreqEnvelope!=NULL) delete (NoteVoicePar[nvoice].FMFreqEnvelope);
NoteVoicePar[nvoice].FMFreqEnvelope=NULL;
if (NoteVoicePar[nvoice].FMAmpEnvelope!=NULL) delete (NoteVoicePar[nvoice].FMAmpEnvelope);
NoteVoicePar[nvoice].FMAmpEnvelope=NULL;
if ((NoteVoicePar[nvoice].FMEnabled!=NONE)&&(NoteVoicePar[nvoice].FMVoice<0)) delete NoteVoicePar[nvoice].FMSmp;
if (NoteVoicePar[nvoice].VoiceOut!=NULL)
for (int i=0;i<SOUND_BUFFER_SIZE;i++) NoteVoicePar[nvoice].VoiceOut[i]=0.0;//do not delete, yet: perhaps is used by another voice
NoteVoicePar[nvoice].Enabled=OFF;
};
/*
* Kill the note
*/
void ADnote::KillNote(){
int nvoice;
for (nvoice=0;nvoice<NUM_VOICES;nvoice++){
if (NoteVoicePar[nvoice].Enabled==ON) KillVoice(nvoice);
//delete VoiceOut
if (NoteVoicePar[nvoice].VoiceOut!=NULL) delete(NoteVoicePar[nvoice].VoiceOut);
NoteVoicePar[nvoice].VoiceOut=NULL;
};
delete (NoteGlobalPar.FreqEnvelope);
delete (NoteGlobalPar.FreqLfo);
delete (NoteGlobalPar.AmpEnvelope);
delete (NoteGlobalPar.AmpLfo);
delete (NoteGlobalPar.GlobalFilterL);
if (stereo!=0) delete (NoteGlobalPar.GlobalFilterR);
delete (NoteGlobalPar.FilterEnvelope);
delete (NoteGlobalPar.FilterLfo);
NoteEnabled=OFF;
};
ADnote::~ADnote(){
if (NoteEnabled==ON) KillNote();
delete [] tmpwave;
delete [] bypassl;
delete [] bypassr;
};
/*
* Init the parameters
*/
void ADnote::initparameters(){
int nvoice,i,tmp[NUM_VOICES];
// Global Parameters
NoteGlobalPar.FreqEnvelope=new Envelope(partparams->GlobalPar.FreqEnvelope,basefreq);
NoteGlobalPar.FreqLfo=new LFO(partparams->GlobalPar.FreqLfo,basefreq);
NoteGlobalPar.AmpEnvelope=new Envelope(partparams->GlobalPar.AmpEnvelope,basefreq);
NoteGlobalPar.AmpLfo=new LFO(partparams->GlobalPar.AmpLfo,basefreq);
NoteGlobalPar.Volume=4.0*pow(0.1,3.0*(1.0-partparams->GlobalPar.PVolume/96.0))//-60 dB .. 0 dB
*VelF(velocity,partparams->GlobalPar.PAmpVelocityScaleFunction);//velocity sensing
NoteGlobalPar.AmpEnvelope->envout_dB();//discard the first envelope output
globalnewamplitude=NoteGlobalPar.Volume*NoteGlobalPar.AmpEnvelope->envout_dB()*NoteGlobalPar.AmpLfo->amplfoout();
NoteGlobalPar.GlobalFilterL=new Filter(partparams->GlobalPar.GlobalFilter);
if (stereo!=0) NoteGlobalPar.GlobalFilterR=new Filter(partparams->GlobalPar.GlobalFilter);
NoteGlobalPar.FilterEnvelope=new Envelope(partparams->GlobalPar.FilterEnvelope,basefreq);
NoteGlobalPar.FilterLfo=new LFO(partparams->GlobalPar.FilterLfo,basefreq);
NoteGlobalPar.FilterQ=partparams->GlobalPar.GlobalFilter->getq();
NoteGlobalPar.FilterFreqTracking=partparams->GlobalPar.GlobalFilter->getfreqtracking(basefreq);
// Forbids the Modulation Voice to be greater or equal than voice
for (i=0;i<NUM_VOICES;i++) if (NoteVoicePar[i].FMVoice>=i) NoteVoicePar[i].FMVoice=-1;
// Voice Parameter init
for (nvoice=0;nvoice<NUM_VOICES;nvoice++){
if (NoteVoicePar[nvoice].Enabled==0) continue;
NoteVoicePar[nvoice].noisetype=partparams->VoicePar[nvoice].Type;
/* Voice Amplitude Parameters Init */
NoteVoicePar[nvoice].Volume=pow(0.1,3.0*(1.0-partparams->VoicePar[nvoice].PVolume/127.0)) // -60 dB .. 0 dB
*VelF(velocity,partparams->VoicePar[nvoice].PAmpVelocityScaleFunction);//velocity
if (partparams->VoicePar[nvoice].PVolumeminus!=0) NoteVoicePar[nvoice].Volume=-NoteVoicePar[nvoice].Volume;
if (partparams->VoicePar[nvoice].PPanning==0)
NoteVoicePar[nvoice].Panning=RND;// random panning
else NoteVoicePar[nvoice].Panning=partparams->VoicePar[nvoice].PPanning/128.0;
newamplitude[nvoice]=1.0;
if (partparams->VoicePar[nvoice].PAmpEnvelopeEnabled!=0) {
NoteVoicePar[nvoice].AmpEnvelope=new Envelope(partparams->VoicePar[nvoice].AmpEnvelope,basefreq);
NoteVoicePar[nvoice].AmpEnvelope->envout_dB();//discard the first envelope sample
newamplitude[nvoice]*=NoteVoicePar[nvoice].AmpEnvelope->envout_dB();
};
if (partparams->VoicePar[nvoice].PAmpLfoEnabled!=0){
NoteVoicePar[nvoice].AmpLfo=new LFO(partparams->VoicePar[nvoice].AmpLfo,basefreq);
newamplitude[nvoice]*=NoteVoicePar[nvoice].AmpLfo->amplfoout();
};
/* Voice Frequency Parameters Init */
if (partparams->VoicePar[nvoice].PFreqEnvelopeEnabled!=0)
NoteVoicePar[nvoice].FreqEnvelope=new Envelope(partparams->VoicePar[nvoice].FreqEnvelope,basefreq);
if (partparams->VoicePar[nvoice].PFreqLfoEnabled!=0) NoteVoicePar[nvoice].FreqLfo=new LFO(partparams->VoicePar[nvoice].FreqLfo,basefreq);
/* Voice Filter Parameters Init */
if (partparams->VoicePar[nvoice].PFilterEnabled!=0){
NoteVoicePar[nvoice].VoiceFilter=new Filter(partparams->VoicePar[nvoice].VoiceFilter);
};
if (partparams->VoicePar[nvoice].PFilterEnvelopeEnabled!=0)
NoteVoicePar[nvoice].FilterEnvelope=new Envelope(partparams->VoicePar[nvoice].FilterEnvelope,basefreq);
if (partparams->VoicePar[nvoice].PFilterLfoEnabled!=0)
NoteVoicePar[nvoice].FilterLfo=new LFO(partparams->VoicePar[nvoice].FilterLfo,basefreq);
NoteVoicePar[nvoice].FilterFreqTracking=partparams->VoicePar[nvoice].VoiceFilter->getfreqtracking(basefreq);
/* Voice Modulation Parameters Init */
if ((NoteVoicePar[nvoice].FMEnabled!=NONE)&&(NoteVoicePar[nvoice].FMVoice<0)){
partparams->VoicePar[nvoice].FMSmp->newrandseed(rand());
NoteVoicePar[nvoice].FMSmp=new REALTYPE[OSCIL_SIZE+OSCIL_SMP_EXTRA_SAMPLES];
//Perform Anti-aliasing only on MORPH or RING MODULATION
int vc=nvoice;
if (partparams->VoicePar[nvoice].PextFMoscil!=-1) vc=partparams->VoicePar[nvoice].PextFMoscil;
REALTYPE tmp=1.0;
if ((partparams->VoicePar[vc].FMSmp->Padaptiveharmonics!=0)||
(NoteVoicePar[nvoice].FMEnabled==MORPH)||
(NoteVoicePar[nvoice].FMEnabled==RING_MOD)){
tmp=getFMvoicebasefreq(nvoice);
};
if (!partparams->GlobalPar.Hrandgrouping) partparams->VoicePar[vc].FMSmp->newrandseed(rand());
oscposhiFM[nvoice]=(oscposhi[nvoice]+partparams->VoicePar[vc].FMSmp->get(NoteVoicePar[nvoice].FMSmp,tmp)) % OSCIL_SIZE;
for (int i=0;i<OSCIL_SMP_EXTRA_SAMPLES;i++) NoteVoicePar[nvoice].FMSmp[OSCIL_SIZE+i]=NoteVoicePar[nvoice].FMSmp[i];
oscposhiFM[nvoice]+=(int)((partparams->VoicePar[nvoice].PFMoscilphase-64.0)/128.0*OSCIL_SIZE+OSCIL_SIZE*4);
oscposhiFM[nvoice]%=OSCIL_SIZE;
};
if (partparams->VoicePar[nvoice].PFMFreqEnvelopeEnabled!=0)
NoteVoicePar[nvoice].FMFreqEnvelope=new Envelope(partparams->VoicePar[nvoice].FMFreqEnvelope,basefreq);
FMnewamplitude[nvoice]=NoteVoicePar[nvoice].FMVolume*ctl->fmamp.relamp;
if (partparams->VoicePar[nvoice].PFMAmpEnvelopeEnabled!=0){
NoteVoicePar[nvoice].FMAmpEnvelope=new Envelope(partparams->VoicePar[nvoice].FMAmpEnvelope,basefreq);
FMnewamplitude[nvoice]*=NoteVoicePar[nvoice].FMAmpEnvelope->envout_dB();
};
};
for (nvoice=0;nvoice<NUM_VOICES;nvoice++){
for (i=nvoice+1;i<NUM_VOICES;i++) tmp[i]=0;
for (i=nvoice+1;i<NUM_VOICES;i++)
if ((NoteVoicePar[i].FMVoice==nvoice)&&(tmp[i]==0)){
NoteVoicePar[nvoice].VoiceOut=new REALTYPE[SOUND_BUFFER_SIZE];
tmp[i]=1;
};
if (NoteVoicePar[nvoice].VoiceOut!=NULL) for (i=0;i<SOUND_BUFFER_SIZE;i++) NoteVoicePar[nvoice].VoiceOut[i]=0.0;
};
};
/*
* Computes the frequency of an oscillator
*/
void ADnote::setfreq(int nvoice,REALTYPE freq){
REALTYPE speed;
freq=fabs(freq);
speed=freq*REALTYPE(OSCIL_SIZE)/(REALTYPE) SAMPLE_RATE;
if (speed>OSCIL_SIZE) speed=OSCIL_SIZE;
F2I(speed,oscfreqhi[nvoice]);
oscfreqlo[nvoice]=speed-floor(speed);
};
/*
* Computes the frequency of an modullator oscillator
*/
void ADnote::setfreqFM(int nvoice,REALTYPE freq){
REALTYPE speed;
freq=fabs(freq);
speed=freq*REALTYPE(OSCIL_SIZE)/(REALTYPE) SAMPLE_RATE;
if (speed>OSCIL_SIZE) speed=OSCIL_SIZE;
F2I(speed,oscfreqhiFM[nvoice]);
oscfreqloFM[nvoice]=speed-floor(speed);
};
/*
* Get Voice base frequency
*/
REALTYPE ADnote::getvoicebasefreq(int nvoice){
REALTYPE detune=NoteVoicePar[nvoice].Detune/100.0+
NoteVoicePar[nvoice].FineDetune/100.0*ctl->bandwidth.relbw*bandwidthDetuneMultiplier+
NoteGlobalPar.Detune/100.0;
if (NoteVoicePar[nvoice].fixedfreq==0) return(this->basefreq*pow(2,detune/12.0));
else {//the fixed freq is enabled
REALTYPE fixedfreq=440.0;
int fixedfreqET=NoteVoicePar[nvoice].fixedfreqET;
if (fixedfreqET!=0) {//if the frequency varies according the keyboard note
REALTYPE tmp=(midinote-69.0)/12.0*(pow(2.0,(fixedfreqET-1)/63.0)-1.0);
if (fixedfreqET<=64) fixedfreq*=pow(2.0,tmp);
else fixedfreq*=pow(3.0,tmp);
};
return(fixedfreq*pow(2.0,detune/12.0));
};
};
/*
* Get Voice's Modullator base frequency
*/
REALTYPE ADnote::getFMvoicebasefreq(int nvoice){
REALTYPE detune=NoteVoicePar[nvoice].FMDetune/100.0;
return(getvoicebasefreq(nvoice)*pow(2,detune/12.0));
};
/*
* Computes all the parameters for each tick
*/
void ADnote::computecurrentparameters(){
int nvoice;
REALTYPE voicefreq,voicepitch,filterpitch,filterfreq,FMfreq,FMrelativepitch,globalpitch,globalfilterpitch;
globalpitch=0.01*(NoteGlobalPar.FreqEnvelope->envout()+
NoteGlobalPar.FreqLfo->lfoout()*ctl->modwheel.relmod);
globaloldamplitude=globalnewamplitude;
globalnewamplitude=NoteGlobalPar.Volume*NoteGlobalPar.AmpEnvelope->envout_dB()*NoteGlobalPar.AmpLfo->amplfoout();
globalfilterpitch=NoteGlobalPar.FilterEnvelope->envout()+NoteGlobalPar.FilterLfo->lfoout()
+NoteGlobalPar.FilterCenterPitch;
REALTYPE tmpfilterfreq=globalfilterpitch+ctl->filtercutoff.relfreq
+NoteGlobalPar.FilterFreqTracking;
tmpfilterfreq=NoteGlobalPar.GlobalFilterL->getrealfreq(tmpfilterfreq);
REALTYPE globalfilterq=NoteGlobalPar.FilterQ*ctl->filterq.relq;
NoteGlobalPar.GlobalFilterL->setfreq_and_q(tmpfilterfreq,globalfilterq);
if (stereo!=0) NoteGlobalPar.GlobalFilterR->setfreq_and_q(tmpfilterfreq,globalfilterq);
//compute the portamento, if it is used by this note
REALTYPE portamentofreqrap=1.0;
if (portamento!=0){//this voice use portamento
portamentofreqrap=ctl->portamento.freqrap;
if (ctl->portamento.used==0){//the portamento has finished
portamento=0;//this note is no longer "portamented"
};
};
//compute parameters for all voices
for (nvoice=0;nvoice<NUM_VOICES;nvoice++){
if (NoteVoicePar[nvoice].Enabled!=ON) continue;
NoteVoicePar[nvoice].DelayTicks-=1;
if (NoteVoicePar[nvoice].DelayTicks>0) continue;
/*******************/
/* Voice Amplitude */
/*******************/
oldamplitude[nvoice]=newamplitude[nvoice];
newamplitude[nvoice]=1.0;
if (NoteVoicePar[nvoice].AmpEnvelope!=NULL)
newamplitude[nvoice]*=NoteVoicePar[nvoice].AmpEnvelope->envout_dB();
if (NoteVoicePar[nvoice].AmpLfo!=NULL)
newamplitude[nvoice]*=NoteVoicePar[nvoice].AmpLfo->amplfoout();
/****************/
/* Voice Filter */
/****************/
if (NoteVoicePar[nvoice].VoiceFilter!=NULL){
filterpitch=NoteVoicePar[nvoice].FilterCenterPitch;
if (NoteVoicePar[nvoice].FilterEnvelope!=NULL)
filterpitch+=NoteVoicePar[nvoice].FilterEnvelope->envout();
if (NoteVoicePar[nvoice].FilterLfo!=NULL)
filterpitch+=NoteVoicePar[nvoice].FilterLfo->lfoout();
filterfreq=filterpitch+NoteVoicePar[nvoice].FilterFreqTracking;
filterfreq=NoteVoicePar[nvoice].VoiceFilter->getrealfreq(filterfreq);
NoteVoicePar[nvoice].VoiceFilter->setfreq(filterfreq);
};
if (NoteVoicePar[nvoice].noisetype==0){//compute only if the voice isn't noise
/*******************/
/* Voice Frequency */
/*******************/
voicepitch=0.0;
if (NoteVoicePar[nvoice].FreqLfo!=NULL)
voicepitch+=NoteVoicePar[nvoice].FreqLfo->lfoout()/100.0
*ctl->bandwidth.relbw;
if (NoteVoicePar[nvoice].FreqEnvelope!=NULL) voicepitch+=NoteVoicePar[nvoice].FreqEnvelope->envout()/100.0;
voicefreq=getvoicebasefreq(nvoice)*pow(2,(voicepitch+globalpitch)/12.0);//Hz frequency
voicefreq*=ctl->pitchwheel.relfreq;//change the frequency by the controller
setfreq(nvoice,voicefreq*portamentofreqrap);
/***************/
/* Modulator */
/***************/
if (NoteVoicePar[nvoice].FMEnabled!=NONE){
FMrelativepitch=NoteVoicePar[nvoice].FMDetune/100.0;
if (NoteVoicePar[nvoice].FMFreqEnvelope!=NULL) FMrelativepitch+=NoteVoicePar[nvoice].FMFreqEnvelope->envout()/100;
FMfreq=pow(2.0,FMrelativepitch/12.0)*voicefreq*portamentofreqrap;
setfreqFM(nvoice,FMfreq);
FMoldamplitude[nvoice]=FMnewamplitude[nvoice];
FMnewamplitude[nvoice]=NoteVoicePar[nvoice].FMVolume*ctl->fmamp.relamp;
if (NoteVoicePar[nvoice].FMAmpEnvelope!=NULL)
FMnewamplitude[nvoice]*=NoteVoicePar[nvoice].FMAmpEnvelope->envout_dB();
};
};
};
time+=(REALTYPE)SOUND_BUFFER_SIZE/(REALTYPE)SAMPLE_RATE;
};
/*
* Fadein in a way that removes clicks but keep sound "punchy"
*/
inline void ADnote::fadein(REALTYPE *smps){
int zerocrossings=0;
for (int i=1;i<SOUND_BUFFER_SIZE;i++)
if ((smps[i-1]<0.0) && (smps[i]>0.0)) zerocrossings++;//this is only the possitive crossings
REALTYPE tmp=(SOUND_BUFFER_SIZE-1.0)/(zerocrossings+1)/3.0;
if (tmp<8.0) tmp=8.0;
int n;
F2I(tmp,n);//how many samples is the fade-in
if (n>SOUND_BUFFER_SIZE) n=SOUND_BUFFER_SIZE;
for (int i=0;i<n;i++) {//fade-in
REALTYPE tmp=0.5-cos((REALTYPE)i/(REALTYPE) n*PI)*0.5;
smps[i]*=tmp;
};
};
/*
* Computes the Oscillator (Without Modulation) - LinearInterpolation
*/
inline void ADnote::ComputeVoiceOscillator_LinearInterpolation(int nvoice){
int i,poshi;
REALTYPE poslo;
poshi=oscposhi[nvoice];
poslo=oscposlo[nvoice];
REALTYPE *smps=NoteVoicePar[nvoice].OscilSmp;
for (i=0;i<SOUND_BUFFER_SIZE;i++){
tmpwave[i]=smps[poshi]*(1.0-poslo)+smps[poshi+1]*poslo;
poslo+=oscfreqlo[nvoice];
if (poslo>=1.0) {
poslo-=1.0;
poshi++;
};
poshi+=oscfreqhi[nvoice];
poshi&=OSCIL_SIZE-1;
};
oscposhi[nvoice]=poshi;
oscposlo[nvoice]=poslo;
};
/*
* Computes the Oscillator (Without Modulation) - CubicInterpolation
*
The differences from the Linear are to little to deserve to be used. This is because I am using a large OSCIL_SIZE (>512)
inline void ADnote::ComputeVoiceOscillator_CubicInterpolation(int nvoice){
int i,poshi;
REALTYPE poslo;
poshi=oscposhi[nvoice];
poslo=oscposlo[nvoice];
REALTYPE *smps=NoteVoicePar[nvoice].OscilSmp;
REALTYPE xm1,x0,x1,x2,a,b,c;
for (i=0;i<SOUND_BUFFER_SIZE;i++){
xm1=smps[poshi];
x0=smps[poshi+1];
x1=smps[poshi+2];
x2=smps[poshi+3];
a=(3.0 * (x0-x1) - xm1 + x2) / 2.0;
b = 2.0*x1 + xm1 - (5.0*x0 + x2) / 2.0;
c = (x1 - xm1) / 2.0;
tmpwave[i]=(((a * poslo) + b) * poslo + c) * poslo + x0;
printf("a\n");
//tmpwave[i]=smps[poshi]*(1.0-poslo)+smps[poshi+1]*poslo;
poslo+=oscfreqlo[nvoice];
if (poslo>=1.0) {
poslo-=1.0;
poshi++;
};
poshi+=oscfreqhi[nvoice];
poshi&=OSCIL_SIZE-1;
};
oscposhi[nvoice]=poshi;
oscposlo[nvoice]=poslo;
};
*/
/*
* Computes the Oscillator (Morphing)
*/
inline void ADnote::ComputeVoiceOscillatorMorph(int nvoice){
int i;
REALTYPE amp;
ComputeVoiceOscillator_LinearInterpolation(nvoice);
if (FMnewamplitude[nvoice]>1.0) FMnewamplitude[nvoice]=1.0;
if (FMoldamplitude[nvoice]>1.0) FMoldamplitude[nvoice]=1.0;
if (NoteVoicePar[nvoice].FMVoice>=0){
//if I use VoiceOut[] as modullator
int FMVoice=NoteVoicePar[nvoice].FMVoice;
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
amp=INTERPOLATE_AMPLITUDE(FMoldamplitude[nvoice]
,FMnewamplitude[nvoice],i,SOUND_BUFFER_SIZE);
tmpwave[i]=tmpwave[i]*(1.0-amp)+amp*NoteVoicePar[FMVoice].VoiceOut[i];
};
} else {
int poshiFM=oscposhiFM[nvoice];
REALTYPE posloFM=oscposloFM[nvoice];
for (i=0;i<SOUND_BUFFER_SIZE;i++){
amp=INTERPOLATE_AMPLITUDE(FMoldamplitude[nvoice]
,FMnewamplitude[nvoice],i,SOUND_BUFFER_SIZE);
tmpwave[i]=tmpwave[i]*(1.0-amp)+amp
*(NoteVoicePar[nvoice].FMSmp[poshiFM]*(1-posloFM)
+NoteVoicePar[nvoice].FMSmp[poshiFM+1]*posloFM);
posloFM+=oscfreqloFM[nvoice];
if (posloFM>=1.0) {
posloFM-=1.0;
poshiFM++;
};
poshiFM+=oscfreqhiFM[nvoice];
poshiFM&=OSCIL_SIZE-1;
};
oscposhiFM[nvoice]=poshiFM;
oscposloFM[nvoice]=posloFM;
};
};
/*
* Computes the Oscillator (Ring Modulation)
*/
inline void ADnote::ComputeVoiceOscillatorRingModulation(int nvoice){
int i;
REALTYPE amp;
ComputeVoiceOscillator_LinearInterpolation(nvoice);
if (FMnewamplitude[nvoice]>1.0) FMnewamplitude[nvoice]=1.0;
if (FMoldamplitude[nvoice]>1.0) FMoldamplitude[nvoice]=1.0;
if (NoteVoicePar[nvoice].FMVoice>=0){
// if I use VoiceOut[] as modullator
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
amp=INTERPOLATE_AMPLITUDE(FMoldamplitude[nvoice]
,FMnewamplitude[nvoice],i,SOUND_BUFFER_SIZE);
int FMVoice=NoteVoicePar[nvoice].FMVoice;
for (i=0;i<SOUND_BUFFER_SIZE;i++)
tmpwave[i]*=(1.0-amp)+amp*NoteVoicePar[FMVoice].VoiceOut[i];
};
} else {
int poshiFM=oscposhiFM[nvoice];
REALTYPE posloFM=oscposloFM[nvoice];
for (i=0;i<SOUND_BUFFER_SIZE;i++){
amp=INTERPOLATE_AMPLITUDE(FMoldamplitude[nvoice]
,FMnewamplitude[nvoice],i,SOUND_BUFFER_SIZE);
tmpwave[i]*=( NoteVoicePar[nvoice].FMSmp[poshiFM]*(1.0-posloFM)
+NoteVoicePar[nvoice].FMSmp[poshiFM+1]*posloFM)*amp
+(1.0-amp);
posloFM+=oscfreqloFM[nvoice];
if (posloFM>=1.0) {
posloFM-=1.0;
poshiFM++;
};
poshiFM+=oscfreqhiFM[nvoice];
poshiFM&=OSCIL_SIZE-1;
};
oscposhiFM[nvoice]=poshiFM;
oscposloFM[nvoice]=posloFM;
};
};
/*
* Computes the Oscillator (Phase Modulation or Frequency Modulation)
*/
inline void ADnote::ComputeVoiceOscillatorFrequencyModulation(int nvoice,int FMmode){
int carposhi;
int i,FMmodfreqhi;
REALTYPE FMmodfreqlo,carposlo;
if (NoteVoicePar[nvoice].FMVoice>=0){
//if I use VoiceOut[] as modulator
for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpwave[i]=NoteVoicePar[NoteVoicePar[nvoice].FMVoice].VoiceOut[i];
} else {
//Compute the modulator and store it in tmpwave[]
int poshiFM=oscposhiFM[nvoice];
REALTYPE posloFM=oscposloFM[nvoice];
for (i=0;i<SOUND_BUFFER_SIZE;i++){
tmpwave[i]=(NoteVoicePar[nvoice].FMSmp[poshiFM]*(1.0-posloFM)
+NoteVoicePar[nvoice].FMSmp[poshiFM+1]*posloFM);
posloFM+=oscfreqloFM[nvoice];
if (posloFM>=1.0) {
posloFM=fmod(posloFM,1.0);
poshiFM++;
};
poshiFM+=oscfreqhiFM[nvoice];
poshiFM&=OSCIL_SIZE-1;
};
oscposhiFM[nvoice]=poshiFM;
oscposloFM[nvoice]=posloFM;
};
// Amplitude interpolation
if (ABOVE_AMPLITUDE_THRESHOLD(FMoldamplitude[nvoice],FMnewamplitude[nvoice])){
for (i=0;i<SOUND_BUFFER_SIZE;i++){
tmpwave[i]*=INTERPOLATE_AMPLITUDE(FMoldamplitude[nvoice]
,FMnewamplitude[nvoice],i,SOUND_BUFFER_SIZE);
};
} else for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpwave[i]*=FMnewamplitude[nvoice];
//normalize makes all sample-rates, oscil_sizes toproduce same sound
if (FMmode!=0){//Frequency modulation
REALTYPE normalize=OSCIL_SIZE/262144.0*44100.0/(REALTYPE)SAMPLE_RATE;
for (i=0;i<SOUND_BUFFER_SIZE;i++){
FMoldsmp[nvoice]=fmod(FMoldsmp[nvoice]+tmpwave[i]*normalize,OSCIL_SIZE);
tmpwave[i]=FMoldsmp[nvoice];
};
} else {//Phase modulation
REALTYPE normalize=OSCIL_SIZE/262144.0;
for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpwave[i]*=normalize;
};
for (i=0;i<SOUND_BUFFER_SIZE;i++){
F2I(tmpwave[i],FMmodfreqhi);
FMmodfreqlo=fmod(tmpwave[i]+0.0000000001,1.0);
if (FMmodfreqhi<0) FMmodfreqlo++;
//carrier
carposhi=oscposhi[nvoice]+FMmodfreqhi;
carposlo=oscposlo[nvoice]+FMmodfreqlo;
if (carposlo>=1.0) {
carposhi++;
carposlo=fmod(carposlo,1.0);
};
carposhi&=(OSCIL_SIZE-1);
tmpwave[i]=NoteVoicePar[nvoice].OscilSmp[carposhi]*(1.0-carposlo)
+NoteVoicePar[nvoice].OscilSmp[carposhi+1]*carposlo;
oscposlo[nvoice]+=oscfreqlo[nvoice];
if (oscposlo[nvoice]>=1.0) {
oscposlo[nvoice]=fmod(oscposlo[nvoice],1.0);
oscposhi[nvoice]++;
};
oscposhi[nvoice]+=oscfreqhi[nvoice];
oscposhi[nvoice]&=OSCIL_SIZE-1;
};
};
/*Calculeaza Oscilatorul cu PITCH MODULATION*/
inline void ADnote::ComputeVoiceOscillatorPitchModulation(int nvoice){
//TODO
};
/*
* Computes the Noise
*/
inline void ADnote::ComputeVoiceNoise(int nvoice){
for (int i=0;i<SOUND_BUFFER_SIZE;i++) tmpwave[i]=RND*2.0-1.0;
};
/*
* Compute the ADnote samples
* Returns 0 if the note is finished
*/
int ADnote::noteout(REALTYPE *outl,REALTYPE *outr){
int i,nvoice;
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
outl[i]=denormalkillbuf[i];
outr[i]=denormalkillbuf[i];
};
if (NoteEnabled==OFF) return(0);
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
bypassl[i]=0.0;
bypassr[i]=0.0;
};
computecurrentparameters();
for (nvoice=0;nvoice<NUM_VOICES;nvoice++){
if ((NoteVoicePar[nvoice].Enabled!=ON) || (NoteVoicePar[nvoice].DelayTicks>0)) continue;
if (NoteVoicePar[nvoice].noisetype==0){//voice mode=sound
switch (NoteVoicePar[nvoice].FMEnabled){
case MORPH:ComputeVoiceOscillatorMorph(nvoice);break;
case RING_MOD:ComputeVoiceOscillatorRingModulation(nvoice);break;
case PHASE_MOD:ComputeVoiceOscillatorFrequencyModulation(nvoice,0);break;
case FREQ_MOD:ComputeVoiceOscillatorFrequencyModulation(nvoice,1);break;
//case PITCH_MOD:ComputeVoiceOscillatorPitchModulation(nvoice);break;
default:ComputeVoiceOscillator_LinearInterpolation(nvoice);
//if (config.cfg.Interpolation) ComputeVoiceOscillator_CubicInterpolation(nvoice);
};
} else ComputeVoiceNoise(nvoice);
// Voice Processing
// Amplitude
if (ABOVE_AMPLITUDE_THRESHOLD(oldamplitude[nvoice],newamplitude[nvoice])){
int rest=SOUND_BUFFER_SIZE;
//test if the amplitude if raising and the difference is high
if ((newamplitude[nvoice]>oldamplitude[nvoice])&&((newamplitude[nvoice]-oldamplitude[nvoice])>0.25)){
rest=10;
if (rest>SOUND_BUFFER_SIZE) rest=SOUND_BUFFER_SIZE;
for (int i=0;i<SOUND_BUFFER_SIZE-rest;i++) tmpwave[i]*=oldamplitude[nvoice];
};
// Amplitude interpolation
for (i=0;i<rest;i++){
tmpwave[i+(SOUND_BUFFER_SIZE-rest)]*=INTERPOLATE_AMPLITUDE(oldamplitude[nvoice]
,newamplitude[nvoice],i,rest);
};
} else for (i=0;i<SOUND_BUFFER_SIZE;i++) tmpwave[i]*=newamplitude[nvoice];
// Fade in
if (firsttick[nvoice]!=0){
fadein(&tmpwave[0]);
firsttick[nvoice]=0;
};
// Filter
if (NoteVoicePar[nvoice].VoiceFilter!=NULL) NoteVoicePar[nvoice].VoiceFilter->filterout(&tmpwave[0]);
//check if the amplitude envelope is finished, if yes, the voice will be fadeout
if (NoteVoicePar[nvoice].AmpEnvelope!=NULL) {
if (NoteVoicePar[nvoice].AmpEnvelope->finished()!=0)
for (i=0;i<SOUND_BUFFER_SIZE;i++)
tmpwave[i]*=1.0-(REALTYPE)i/(REALTYPE)SOUND_BUFFER_SIZE;
//the voice is killed later
};
// Put the ADnote samples in VoiceOut (without appling Global volume, because I wish to use this voice as a modullator)
if (NoteVoicePar[nvoice].VoiceOut!=NULL)
for (i=0;i<SOUND_BUFFER_SIZE;i++) NoteVoicePar[nvoice].VoiceOut[i]=tmpwave[i];
// Add the voice that do not bypass the filter to out
if (NoteVoicePar[nvoice].filterbypass==0){//no bypass
if (stereo==0) for (i=0;i<SOUND_BUFFER_SIZE;i++) outl[i]+=tmpwave[i]*NoteVoicePar[nvoice].Volume;//mono
else for (i=0;i<SOUND_BUFFER_SIZE;i++) {//stereo
outl[i]+=tmpwave[i]*NoteVoicePar[nvoice].Volume*NoteVoicePar[nvoice].Panning*2.0;
outr[i]+=tmpwave[i]*NoteVoicePar[nvoice].Volume*(1.0-NoteVoicePar[nvoice].Panning)*2.0;
};
} else {//bypass the filter
if (stereo==0) for (i=0;i<SOUND_BUFFER_SIZE;i++) bypassl[i]+=tmpwave[i]*NoteVoicePar[nvoice].Volume;//mono
else for (i=0;i<SOUND_BUFFER_SIZE;i++) {//stereo
bypassl[i]+=tmpwave[i]*NoteVoicePar[nvoice].Volume*NoteVoicePar[nvoice].Panning*2.0;
bypassr[i]+=tmpwave[i]*NoteVoicePar[nvoice].Volume*(1.0-NoteVoicePar[nvoice].Panning)*2.0;
};
};
// chech if there is necesary to proces the voice longer (if the Amplitude envelope isn't finished)
if (NoteVoicePar[nvoice].AmpEnvelope!=NULL) {
if (NoteVoicePar[nvoice].AmpEnvelope->finished()!=0) KillVoice(nvoice);
};
};
//Processing Global parameters
NoteGlobalPar.GlobalFilterL->filterout(&outl[0]);
if (stereo==0) {
for (i=0;i<SOUND_BUFFER_SIZE;i++) {//set the right channel=left channel
outr[i]=outl[i];
bypassr[i]=bypassl[i];
}
} else NoteGlobalPar.GlobalFilterR->filterout(&outr[0]);
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
outl[i]+=bypassl[i];
outr[i]+=bypassr[i];
};
if (ABOVE_AMPLITUDE_THRESHOLD(globaloldamplitude,globalnewamplitude)){
// Amplitude Interpolation
for (i=0;i<SOUND_BUFFER_SIZE;i++){
REALTYPE tmpvol=INTERPOLATE_AMPLITUDE(globaloldamplitude
,globalnewamplitude,i,SOUND_BUFFER_SIZE);
outl[i]*=tmpvol*NoteGlobalPar.Panning;
outr[i]*=tmpvol*(1.0-NoteGlobalPar.Panning);
};
} else {
for (i=0;i<SOUND_BUFFER_SIZE;i++) {
outl[i]*=globalnewamplitude*NoteGlobalPar.Panning;
outr[i]*=globalnewamplitude*(1.0-NoteGlobalPar.Panning);
};
};
//Apply the punch
if (NoteGlobalPar.Punch.Enabled!=0){
for (i=0;i<SOUND_BUFFER_SIZE;i++){
REALTYPE punchamp=NoteGlobalPar.Punch.initialvalue*NoteGlobalPar.Punch.t+1.0;
outl[i]*=punchamp;
outr[i]*=punchamp;
NoteGlobalPar.Punch.t-=NoteGlobalPar.Punch.dt;
if (NoteGlobalPar.Punch.t<0.0) {
NoteGlobalPar.Punch.Enabled=0;
break;
};
};
};
// Check if the global amplitude is finished.
// If it does, disable the note
if (NoteGlobalPar.AmpEnvelope->finished()!=0) {
for (i=0;i<SOUND_BUFFER_SIZE;i++) {//fade-out
REALTYPE tmp=1.0-(REALTYPE)i/(REALTYPE)SOUND_BUFFER_SIZE;
outl[i]*=tmp;
outr[i]*=tmp;
};
KillNote();
};
return(1);
};
/*
* Relase the key (NoteOff)
*/
void ADnote::relasekey(){
int nvoice;
for (nvoice=0;nvoice<NUM_VOICES;nvoice++){
if (NoteVoicePar[nvoice].Enabled==0) continue;
if (NoteVoicePar[nvoice].AmpEnvelope!=NULL) NoteVoicePar[nvoice].AmpEnvelope->relasekey();
if (NoteVoicePar[nvoice].FreqEnvelope!=NULL) NoteVoicePar[nvoice].FreqEnvelope->relasekey();
if (NoteVoicePar[nvoice].FilterEnvelope!=NULL) NoteVoicePar[nvoice].FilterEnvelope->relasekey();
if (NoteVoicePar[nvoice].FMFreqEnvelope!=NULL) NoteVoicePar[nvoice].FMFreqEnvelope->relasekey();
if (NoteVoicePar[nvoice].FMAmpEnvelope!=NULL) NoteVoicePar[nvoice].FMAmpEnvelope->relasekey();
};
NoteGlobalPar.FreqEnvelope->relasekey();
NoteGlobalPar.FilterEnvelope->relasekey();
NoteGlobalPar.AmpEnvelope->relasekey();
};
/*
* Check if the note is finished
*/
int ADnote::finished(){
if (NoteEnabled==ON) return(0);
else return(1);
};